package hh.util;

import hh.util.time.TimeUtil;

import java.io.Serializable;
import java.math.BigDecimal;

/**
 * 数字相关工具类， 如数字转中文，double相除，取整等等
 *
 * @author huanghuai
 * @date 2020/9/14
 */
public class NumberUtil implements Serializable {
    private static final long serialVersionUID = 8789986437241944385L;

    private NumberUtil() {
    }

    public static final long ge = 1;
    public static final long shi = ge * 10;
    public static final long bai = shi * 10;
    public static final long qian = bai * 10;
    public static final long wan = qian * 10;
    public static final long shiwan = wan * 10;
    public static final long baiwan = shiwan * 10;
    public static final long qianwan = baiwan * 10;
    public static final long yi = qianwan * 10;
    public static final long shiyi = yi * 10;
    public static final long baiyi = shiyi * 10;
    public static final long qianyi = baiyi * 10;
    public static final long wanyi = qianyi * 10;

    private static final String[] cnNumUnit = {"万亿", "亿", "万", ""};
    /**
     * 中文大写 <br>
     * 10             8     2  3  3   4   9   8   5
     * 十 万 亿 五 千 八百 二十 三 万 四千 九百 八十 五 <br>
     * 实在不知道怎么命名，又方便记忆了，所以用拼音
     */
    private static final String[] wanUnit = {"亿", "万", ""};
    private static final String[] qianUnit = {"仟", "佰", "拾", ""};
    private static final String[] geUnit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};

    public static void main(String[] args) {
        System.out.println(CommonUtil.getLineInfo(1));
        long s = System.currentTimeMillis();
        long count = 1000_0000_0000_0000L - 1; //10000 58234985L 58230905L 10_0000_0000_0000L
        System.out.println(toCnBigNum(count));
        System.out.println(toCn(count));
        System.out.println(pretty(12345678)); // 100,000 1,000 1,000,000 10,000,000
        System.out.println(TimeUtil.countTimeCn(s - 1000000));
    }


    public static String toBinary64(long num) {
        String s = Long.toBinaryString(num);
        int i = 64 - s.length();
        String repeat = StringUtil.repeat("0", i);
        return repeat + s;
    }
    public static String toBinary32(int num) {
        String s = Long.toBinaryString(num);
        int i = 32 - s.length();
        String repeat = StringUtil.repeat("0", i);
        return repeat + s;
    }
    public static String toBinaryPretty64(long num) {
        String s = Long.toBinaryString(num);
        int i = 64 - s.length();
        String repeat = StringUtil.repeat("0", i);
        return StringUtil.join(repeat + s,8," ");
    }
    public static String toBinaryPretty32(int num) {
        String s = Integer.toBinaryString(num);
        int i = 32 - s.length();
        String repeat = StringUtil.repeat("0", i);
        return StringUtil.join(repeat + s,8," ");
    }


    /**
     * xxx万亿xxx亿xxxx千万xxx
     */
    public static String toCn(long num) {
        long[] numUnitArr = getNumUnitArr(num);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < numUnitArr.length; i++) {
            if (numUnitArr[i] != 0) {
                sb.append(numUnitArr[i]).append(cnNumUnit[i]);
            }
        }
        return sb.toString();
    }

    /**
     * 100000 -> 1,000,000
     */
    public static String pretty(long num) {
        String strNum = num + "";
        int length = strNum.length();
        char[] chars = new char[length + ((length - 1) / 3)];
        int index = length % 3;
        if (index == 0) {
            index = 3;
        }
        int j = 0;
        for (int i = 0; i < length; i++) {
            if (i == index) {
                chars[i + j] = ',';
                index += 3;
                j++;
            }
            chars[i + j] = strNum.charAt(i);
        }
        return new String(chars);
    }

    /**
     * 中文大写货币单位
     */
    public static String toCnBigNum(long num) {
        // xxx亿xxx万xxx
        long[] wanUnitArr = getWanUnitArr(num);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < wanUnitArr.length; i++) {
            // xxx数字
            if (wanUnitArr[i] != 0) {
                //分解千
                appendQian(wanUnitArr[i], sb, true);
                // 亿、万 单位
                sb.append(wanUnit[i]);
            }
        }
        return sb.toString();
    }

    private static void appendQian(long num, StringBuilder sb, boolean hasBefore) {
        long[] qianUnitArr = getQianUnitArr(num);
        boolean hasAppendZero = false;
        for (int j = 0; j < qianUnitArr.length; j++) {
            int n = (int) qianUnitArr[j];
            if (n == 0) {
                // 3000亿是不需要 0的
                boolean zhengShu = qianUnitArr[0] != 0 && qianUnitArr[1] == 0 && qianUnitArr[2] == 0 && qianUnitArr[3] == 0;
                if (!hasAppendZero && sb.length() != 0 && !zhengShu && hasBefore) {
                    hasAppendZero = true;
                    sb.append(geUnit[0]);
                }
            } else {
                hasAppendZero = false;
                // x百、x十
                if (n >= 10) {
                    appendWan(n * 1000, sb, false);
                } else {
                    sb.append(geUnit[n]).append(qianUnit[j]);
                }
            }
        }
    }

    private static void appendWan(long num, StringBuilder sb, boolean hasBefore) {
        // xxx亿xxx万xxx
        long[] wanUnitArr = getWanUnitArr(num);
        for (int i = 0; i < wanUnitArr.length; i++) {
            // xxx数字
            if (wanUnitArr[i] != 0) {
                //分解千
                appendQian(wanUnitArr[i], sb, true);
                // 亿、万
                sb.append(wanUnit[i]);
            }
        }
    }

    private static long[] getWanUnitArr(long num) {
        long y = num / yi;
        long w = (num = num % yi) / wan;
        long g = num % wan;
        return new long[]{y, w, g};
    }

    private static long[] getQianUnitArr(long num) {
        long q = num / qian;
        long b = (num = num % qian) / bai;
        long s = (num = num % bai) / shi;
        long g = num % shi;
        return new long[]{q, b, s, g};
    }

    private static long[] getNumUnitArr(long num) {
        return new long[]{
                num / wanyi,
                (num = num % wanyi) / yi,
                (num = num % yi) / wan,
                num % wan};
    }


    /**
     * formatDouble(2.12, 1) --> 2.1
     */
    public static double formatDouble(double d, int retain) {
        // 0/0 1/0 -1/0
        if (Double.isNaN(d) || Double.isInfinite(d)) {
            return 0d;
        }
        BigDecimal b = new BigDecimal(d);
        return b.setScale(retain, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * getRatio(2.54,10,1) --> 2.54/10保留一位小数 --> 0.2  <br>
     * 发生任何异常,都返回0
     *
     * @param i      分子
     * @param total  分母
     * @param retain 保留小数位
     */
    public static double getRatio(Number i, Number total, int retain) {
        if (i == null || total == null) {
            return 0;
        }
        double ratio = i.doubleValue() / total.doubleValue();
        if (isNaNOrInfinity(ratio)) {
            return 0;
        }
        BigDecimal b = new BigDecimal(ratio);
        return b.setScale(retain, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    @SuppressWarnings("all")
    public static boolean isNaNOrInfinity(double v) {
        return (v == Double.POSITIVE_INFINITY) || (v == Double.NEGATIVE_INFINITY) || (v != v);
    }


}
